﻿using System;
using System.IO;
using System.Text;
using NPOI;
using NPOI.SS.UserModel;
using NPOI.HSSF.UserModel;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace RaceHelper
{
    struct Rank
    {
        public string name;
        public int score;
    }
    public class RaceHelper
    {
        //设置目标路径（台式机）
        public string excelPath = @"D:\Desktop\TuringInfo\ExcelOperater\test.xls";
        public string unityPath = @"C:\Users\Cno\turing_alpha_1024\Game";
        public string libraryPath = @"D:\Desktop\TuringInfo\ExcelOperater\Library";
        public string electronPath = @"D:\Desktop\TuringInfo\turing-ranking-pad\dist_electron\win-unpacked\turing-ranking-pad.exe";

        /*
        //设置路径（笔记本）
        public string excelPath = @"D:\Desktop\turing_alpha_1031\test.xls";
        public string unityPath = @"D:\Desktop\turing_alpha_1031\Game";
        public string libraryPath = @"D:\Desktop\turing_alpha_1031\Library";
        */

        public RaceHelper()
        {
            if (File.Exists(@"D:\Desktop\turing_alpha_1031\test.xls"))
            {
                Console.WriteLine(@"使用D:\Desktop\turing_alpha_1031作为运行目录");
                excelPath = @"D:\Desktop\turing_alpha_1031\test.xls";
                unityPath = @"D:\Desktop\turing_alpha_1031\Game";
                libraryPath = @"D:\Desktop\turing_alpha_1031\Library";
                electronPath = @"D:\Desktop\turing_alpha_1031\win-unpacked\turing-ranking-pad.exe";
            }
            else if (File.Exists(@"D:\Turing\test.xls"))
            {
                Console.WriteLine(@"使用D:\Turing作为运行目录");
                excelPath = @"D:\Turing\test.xls";
                unityPath = @"D:\Turing\Game";
                libraryPath = @"D:\Turing\Library";
                electronPath = @"D:\Turing\win-unpacked\turing-ranking-pad.exe";
            }
        }

        [DllImport("kernel32.dll")]
        public static extern int WinExec(string exeName, int operType);
        FileStream fs_open, fs_write;
        HSSFWorkbook wk;

        //大Json
        public JObject jObject;
        System.UInt64 jobjectNum = 0;

        //录制文件的保存位置
        private string recordDir = @"D:\RecordFiles";

        //表格的开关函数
        void read_open()
        {
            fs_open = File.OpenRead(excelPath);
            wk = new HSSFWorkbook(fs_open);
        }
        void read_close()
        {
            wk.Clear();
            fs_open.Close();
        }

        void write_open()
        {
            read_open();
        }
        void write_close()
        {
            fs_open.Close();
            fs_write = File.Create(excelPath);
            wk.Write(fs_write);
            wk.Clear();
            fs_write.Close();
        }

        //获取本次需要淘汰的队伍数量
        public int getRaceWeedOutNum()
        {
            read_open();
            ISheet sheet = wk.GetSheetAt(0);
            int ret = Convert.ToInt32(sheet.GetRow(1).GetCell(1).ToString());
            read_close();
            return ret;
        }
        //获取比赛需要的倍速
        public int getRaceSpeed()
        {
            read_open();
            ISheet sheet = wk.GetSheetAt(0);
            int ret = Convert.ToInt32(sheet.GetRow(1).GetCell(2).ToString());
            read_close();
            return ret;
        }
        //获取比赛信息（0比赛编号，1-4队伍编号）
        public int[] getRaceInfo()
        {
            int raceSum = getRaceNum();
            int[] ret = new int[5];
            read_open();
            ISheet sheet0 = wk.GetSheetAt(0);
            ISheet sheet1 = wk.GetSheetAt(1);
            ret[0] = Convert.ToInt32(sheet0.GetRow(1).GetCell(0).ToString()) + 1;
            //校验赛事是否已经到底
            if (ret[0] <= raceSum)
            {
                for (int i = 1; i < 5; i++)
                {
                    ret[i] = Convert.ToInt32(sheet1.GetRow(ret[0]).GetCell(i).ToString());
                }
            }

            read_close();
            return ret;
        }
        //记录比赛信息
        public void setRaceResult(int raceID, int[] scores, bool[] death, string[] teamName, int[] failTimes)
        {
            int[] raceInfo = getRaceInfo();
            write_open();
            ISheet sheet0 = wk.GetSheetAt(0);
            ISheet sheet1 = wk.GetSheetAt(1);
            ISheet sheet2 = wk.GetSheetAt(2);

            //检查比赛信息是否匹配
            if (raceID != raceInfo[0])
            {
                //sheet1.GetRow(raceID).CreateCell(21).SetCellValue("raceID not match:should be " + raceInfo[0] + " but got " + raceID);
                return;
            }

            //写入比赛信息
            for(int i = 1; i < 5; i++)
            {
                //记录得分
                sheet1.GetRow(raceID).CreateCell(4 + i).SetCellValue(scores[i]);
                //记录死亡情况
                if (death[i]) sheet1.GetRow(raceID).CreateCell(8 + i).SetCellValue(1);
                //对名称检查失败的队记录队名
                if (!checkTeamName(raceInfo[i], teamName[i]))
                {
                    sheet1.GetRow(raceID).CreateCell(12 + i).SetCellValue(teamName[i]);
                }
                else
                {
                    //累计队伍得分
                    ICell cell = sheet2.GetRow(raceInfo[i]).GetCell(2);
                    if (cell == null)
                    {
                        sheet2.GetRow(raceInfo[i]).CreateCell(2).SetCellValue(0);
                        cell = sheet2.GetRow(raceInfo[i]).GetCell(2);
                    }
                    cell.SetCellValue(Convert.ToInt32(cell.ToString()) + scores[i]);

                    //累计队伍比赛场数
                    cell = sheet2.GetRow(raceInfo[i]).GetCell(3);
                    if (cell == null)
                    {
                        sheet2.GetRow(raceInfo[i]).CreateCell(3).SetCellValue(0);
                        cell = sheet2.GetRow(raceInfo[i]).GetCell(3);
                    }
                    cell.SetCellValue(Convert.ToInt32(cell.ToString()) + 1);

                }
                //记录超时次数
                if (failTimes[i] != 0)
                {
                    sheet1.GetRow(raceID).CreateCell(16 + i).SetCellValue(failTimes[i]);
                }
            }

            //更新最后一场完成比赛编号
            sheet0.GetRow(1).CreateCell(0).SetCellValue(raceID);

            write_close();
        }
        bool checkTeamName(int teamID,string teamName) //被调用时必须确保wk已被打开
        {
            ISheet sheet2 = wk.GetSheetAt(2);
            if (sheet2.GetRow(teamID).GetCell(1).ToString() == teamName) return true;
            else return false;
        }
        //提供给外部使用的校验队名与编号是否一致
        public bool checkRaceTeamName(int teamID, string teamName)
        {
            read_open();
            bool ret = checkTeamName(teamID, teamName);
            read_close();
            return ret;
        }
        public string getRaceTeamName(int teamID)
        {
            read_open();
            ISheet sheet2 = wk.GetSheetAt(2);
            string ret = sheet2.GetRow(teamID).GetCell(1).ToString();
            read_close();
            return ret;
        }
        //以比赛模式运行Unity平台
        public void execPlatform()
        {
            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = unityPath + "\\Turing2020.exe";
            info.Arguments = "-race";
            info.WindowStyle = ProcessWindowStyle.Minimized;
            Process pro = Process.Start(info);
            Console.WriteLine("已启动平台，等待平台退出...");
            pro.WaitForExit();
            Console.WriteLine("平台已退出");
        }
        public void execPlatform(string args)
        {
            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = unityPath + "\\Turing2020.exe";
            info.Arguments = args;
            info.WindowStyle = ProcessWindowStyle.Minimized;
            Process pro = Process.Start(info);
            Console.WriteLine("已启动平台，等待平台退出...");
            pro.WaitForExit();
            Console.WriteLine("平台已退出");
        }
        public bool prepDLL() //赛前必须使用checkLibrary完成代码库校验
        {
            int[] raceInfo = getRaceInfo();
            for (int i = 1; i < 5; i++)
            {
                if (File.Exists(libraryPath + "\\" + raceInfo[i] + "\\DLL\\Player" + i + ".dll"))
                {
                    File.Copy(libraryPath + "\\" + raceInfo[i] + "\\DLL\\Player" + i + ".dll", unityPath + "\\Turing2020_Data\\Managed\\Player" + i + ".dll", true);
                }
                else
                {
                    Console.WriteLine("错误：在复制选手" + i + "(id=" + raceInfo[i] + ")的dll时出现了文件缺失，请检查！");
                    return false;
                }
            }
            return true;
        }
        public void checkLibrary(int teamNum)
        {
            for(int i = 1; i <= teamNum; i++)
            {
                for (int j = 1; j < 5; j++)
                {
                    if (!File.Exists(libraryPath + "\\" + i.ToString() + "\\DLL\\Player" + j.ToString() + ".dll"))
                    {
                        Console.WriteLine("选手" + i + "的" + j + "号库文件缺失");
                    }
                }
            }
            Console.WriteLine("库目录校验完成");
        }
        public int getRaceNum()
        {
            read_open();
            ISheet sheet1 = wk.GetSheetAt(1);
            int ret = sheet1.LastRowNum;
            read_close();
            return ret;
        }
        public int getTeamNum()
        {
            read_open();
            ISheet sheet2 = wk.GetSheetAt(2);
            int ret = sheet2.LastRowNum;
            read_close();
            return ret;
        }
        public string[,] getRankingList()
        {
            read_open();
            //初始化
            ISheet sheet2 = wk.GetSheetAt(2);
            int num = sheet2.LastRowNum;
            string[,] ret = new string[num,2];
            List<Rank> ranks = new List<Rank>();

            //读取excel写入ranks列表
            for(int i = 1; i <= num; i++)
            {
                Rank rank = new Rank();
                rank.name = sheet2.GetRow(i).GetCell(1).ToString();
                ICell cell = sheet2.GetRow(i).GetCell(2);
                if (cell == null)
                {
                    rank.score = -1;
                }
                else
                {
                    //Console.WriteLine("Proc" + i + ",value=" + cell.ToString());
                    rank.score = Convert.ToInt32(cell.ToString()) / Convert.ToInt32(sheet2.GetRow(i).GetCell(3).ToString()); //计算平均分
                }
                ranks.Add(rank);
            }

            //对ranks数组排序
            ranks.Sort(delegate (Rank a, Rank b)
            {
                return b.score - a.score;
            });

            //将结果转到返回的数组中
            for(int i = 0; i < num; i++)
            {
                ret[i, 0] = ranks[i].name;
                ret[i, 1] = ranks[i].score.ToString();
                if (ret[i, 1] == "-1") ret[i, 1] = "未上场";
            }

            read_close();
            return ret;
        }
        public void getRankingListToJson()
        {
            //获取信息
            string[,] st = getRankingList();
            int num = getTeamNum();

            //构造并填充两份Json数组
            JArray names = new JArray();
            JArray scores = new JArray();
            for(int i = 0; i < num; i++)
            {
                names.Add(st[i, 0]);
                scores.Add(st[i, 1]);
            }

            //将数组装填至Json对象中
            JObject o = new JObject();
            o["names"] = names;
            o["scores"] = scores;

            //将Json保存至D:\Rank.json
            FileStream fs = File.Create(@"D:\Rank.json");
            byte[] buffer = Encoding.UTF8.GetBytes(o.ToString());
            fs.Write(buffer,0,buffer.Length);
            fs.Close();

            //Console.WriteLine(o);
        }
        public void recordAction(string funcName,int execTime,int[] args)
        {
            //检查大Json是否被初始化
            if (jObject == null) jObject = new JObject();

            //初始化并填充Json对象
            JObject o = new JObject();
            o["funcName"] = funcName;
            o["execTime"] = execTime;
            JArray jargs = new JArray();
            jargs.Add(args[0]);
            jargs.Add(args[1]);
            o["args"] = jargs;

            //将此对象追加到大Json中
            jObject.Add(new JProperty(jobjectNum.ToString(),o));

            //已有对象数量++
            jobjectNum++;
        }
        public void saveAction(int raceNum)
        {
            //检查D:\RecordFiles目录是否存在
            if (!Directory.Exists(recordDir))
            {
                Directory.CreateDirectory(recordDir); 
            }

            //将Json保存至D:\RecordFiles\raceNum.json
            FileStream fs = File.Create(recordDir + "\\" + raceNum + ".json");
            byte[] buffer = Encoding.UTF8.GetBytes(jObject.ToString());
            fs.Write(buffer, 0, buffer.Length);
            fs.Close();

            //清空jObject
            jObject = null;
            jobjectNum = 0;
        }
        public void checkActions()
        {
            int raceNum = getRaceNum();
            Console.WriteLine("=======开始校验Action库=======");
            for (int i = 1; i <= raceNum; i++)
            {
                if (!File.Exists(recordDir + "\\" + i.ToString() + ".json")) Console.WriteLine("缺失Action文件：" + i);
            }
            Console.WriteLine("=======结束校验Action库=======");
        }
        public JObject readAction(int raceNum)
        {
            //打开文件并解析为Json
            StreamReader fs_json = File.OpenText(recordDir + "\\" + raceNum + ".json");
            JsonTextReader reader = new JsonTextReader(fs_json);
            JObject o = (JObject)JToken.ReadFrom(reader);
            //Console.WriteLine(o);
            fs_json.Close();
            return o;
        }
        public void skipRace()
        {
            write_open();
            ISheet sheet0 = wk.GetSheetAt(0);
            int num = Convert.ToInt32(sheet0.GetRow(1).GetCell(0).ToString()) + 1;
            sheet0.GetRow(1).GetCell(0).SetCellValue(num);
            write_close();
        }
        public string getRaceInfoText(int num,bool isFinal)
        {
            if (isFinal)
            {
                int r2 = 0, r3 = 0;
                if (1 <= num && num <= 8)
                {
                    r2 = (int)((num + 1) / 2);
                    r3 = 2 - num % 2;
                    return "第一轮小组赛-第" + r2 + "组-第" + r3 + "/2场";
                }
                else if (9 <= num && num <= 14)
                {
                    num -= 8;
                    r2 = (int)((num + 1) / 2);
                    r3 = 2 - num % 2;
                    return "第二轮小组赛-第" + r2 + "组-第" + r3 + "/2场";
                }
                else if (15 <= num && num <= 20)
                {
                    num -= 14;
                    return "决赛-第" + num + "/6场";
                }
            }
            return num + " / " + getRaceNum().ToString();
        }
        public void showResult(int num)
        {
            //复制json
            if (File.Exists(@"D:\Rank - " + num + ".json"))
            {
                File.Copy(@"D:\Rank - " + num + ".json", @"D:\Rank.json", true);
            }
            else
            {
                Console.WriteLine("不存在" + num + "的结果Json");
            }

            //运行Electron
            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = electronPath;
            info.WindowStyle = ProcessWindowStyle.Minimized;
            Process pro = Process.Start(info);
            pro.WaitForExit();
        }
    }
}
